home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-serious-
/
misc
/
mmulib
/
c_sources
/
musetcachemode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-11-29
|
22KB
|
448 lines
/*****************************************************************
** MuSetCacheMode **
** **
** Reprogram MMU tables selectively. **
** Release 40.6, © 1999 THOR-Software inc. **
** 9.8.1999 Thomas Richter **
*****************************************************************/
/// Includes
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <mmu/mmubase.h>
#include <mmu/context.h>
#include <mmu/mmutags.h>
#include <workbench/startup.h>
#include <thor/conversions.h>
#include <proto/exec.h>
#include <proto/mmu.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <string.h>
///
/// Defines
#define STRINGDATE "8.8.99"
#define STRINGVERSION "40.6"
#define TEMPLATE "ADDRESS=FROM/A,SIZE/A,COPYBACK/S,WRITETHROUGH/S,NOCACHESERIALIZED=CACHEINHIBIT/S,NONSERIAL/S,NOCACHE=IMPRECISE/S,VALID/S,INVALID/S,BLANK/S,IO=IOSPACE/S,NOIO=NOIOSPACE/S,ROM/S,NOROM/S,WRITEPROTECTED/S,NOTWRITEPROTECTED/S,USERONLY/S,SUPERVISORONLY/S,VERBOSE/S"
#define CACHEFLAGS (MAPP_CACHEINHIBIT|MAPP_NONSERIALIZED|MAPP_IMPRECISE|MAPP_COPYBACK)
#define ROMFLAGS (MAPP_ROM|MAPP_WRITEPROTECTED)
#define OPT_ADDRESS 0
#define OPT_SIZE 1
#define OPT_COPYBACK 2
#define OPT_WRITETHROUGH 3
#define OPT_NOCACHE 4
#define OPT_NOCACHESERIALIZED 5
#define OPT_NOCACHEIMPRECISE 6
#define OPT_VALID 7
#define OPT_INVALID 8
#define OPT_BLANK 9
#define OPT_IO 10
#define OPT_NOIO 11
#define OPT_ROM 12
#define OPT_NOROM 13
#define OPT_WRITEPROTECTED 14
#define OPT_NOTWRITEPROTECTED 15
#define OPT_USERONLY 16
#define OPT_SUPERVISORONLY 17
#define OPT_VERBOSE 18
#define OPT_WINDOW 19
#define OPT_COUNT 20
#define WHICH_ALL 3
#define WHICH_USER 1
#define WHICH_SUPER 2
///
/// Statics
struct MMUBase *MMUBase;
struct DosLibrary *DOSBase;
struct ExecBase *SysBase;
struct Library *IconBase;
///
/// Protos
int __asm __saveds main(void);
int SetCacheMode(ULONG from,ULONG size,ULONG flags,ULONG mask,ULONG which);
struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp);
int SetCache(struct MMUContext *ctx,ULONG from,ULONG size,ULONG flags,ULONG mask);
///
char version[]="$VER: MuSetCacheMode " STRINGVERSION " (" STRINGDATE ") © THOR";
/// main
int __asm __saveds main(void)
{
LONG args[OPT_COUNT];
struct RDArgs *rd,*myrd;
struct Process *proc;
int rc=20;
LONG err;
struct WBStartup *msg;
BPTR oldout;
struct MsgPort *oldconsole;
LONG flags,which;
char *whichmsg;
int from=0,size=0;
ULONG mask;
char flagsmsg[256];
SysBase=*((struct ExecBase **)(4L));
memset(args,0,sizeof(LONG)*OPT_COUNT);
flagsmsg[0]='\0'; /* Clear this string */
/* Wait for the workbench startup, if any */
proc=(struct Process *)FindTask(NULL);
if (!(proc->pr_CLI)) {
WaitPort(&(proc->pr_MsgPort));
msg=(struct WBStartup *)GetMsg(&(proc->pr_MsgPort));
} else msg=NULL;
if (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37L)) {
if (MMUBase=(struct MMUBase *)OpenLibrary("mmu.library",0L)) {
err=ERROR_REQUIRED_ARG_MISSING;
myrd=NULL; /* reset the temporary ReadArgs */
oldout=NULL;
oldconsole=NULL;
if (msg) {
oldout=SelectOutput(NULL);
oldconsole=SetConsoleTask(NULL);
rd=ReadTTArgs(msg,args,&myrd);
} else rd=ReadArgs(TEMPLATE,args,NULL);
if (rd) {
if (!GetMMUType()) {
Printf("MuSetCacheMode requires a working MMU.\n");
err=10;
} else {
err=0;
if (args[OPT_ADDRESS]==NULL || args[OPT_SIZE]==NULL)
err=ERROR_REQUIRED_ARG_MISSING;
if (err==0) {
if (!StrToL((char *)(args[OPT_ADDRESS]),NULL,&from,16))
err=ERROR_BAD_NUMBER;
if (!StrToL((char *)(args[OPT_SIZE]),NULL,&size,16)) {
err=ERROR_BAD_NUMBER;
} else if (size==0) err=ERROR_BAD_NUMBER;
}
if (err==0) {
flags=0;
mask=0;
if (args[OPT_VALID]) {
mask |= MAPP_INVALID | MAPP_BLANK | MAPP_REPAIRABLE;
strcat(flagsmsg,"valid ");
}
if (args[OPT_IO]) {
flags &= ~CACHEFLAGS;
flags |= MAPP_IO|MAPP_CACHEINHIBIT;
mask |= MAPP_IO|CACHEFLAGS;
strcat(flagsmsg,"IO space ");
}
if (args[OPT_NOIO]) {
mask |= MAPP_IO;
flags &= ~MAPP_IO;
strcat(flagsmsg,"memory space ");
}
if (args[OPT_COPYBACK]) {
flags &= ~CACHEFLAGS;
flags |= MAPP_COPYBACK;
mask |= CACHEFLAGS;
strcat(flagsmsg,"copyback ");
}
if (args[OPT_WRITETHROUGH]) {
flags &= ~CACHEFLAGS; /* writethrough is the default */
mask |= CACHEFLAGS;
strcat(flagsmsg,"writethrough ");
}
if (args[OPT_NOCACHE]) {
flags &= ~CACHEFLAGS;
flags |= MAPP_CACHEINHIBIT;
mask |= CACHEFLAGS;
strcat(flagsmsg,"cacheinhibit ");
}
if (args[OPT_NOCACHESERIALIZED]) {
flags &= ~CACHEFLAGS;
flags |= MAPP_CACHEINHIBIT | MAPP_NONSERIALIZED;
mask |= CACHEFLAGS;
strcat(flagsmsg,"cacheinhibit non-serialized ");
}
if (args[OPT_NOCACHEIMPRECISE]) {
flags &= ~CACHEFLAGS;
flags |= MAPP_CACHEINHIBIT | MAPP_IMPRECISE;
mask |= CACHEFLAGS;
strcat(flagsmsg,"cacheinhibit imprecise ");
}
if (args[OPT_ROM]) {
flags &= ~ROMFLAGS;
flags |= MAPP_ROM;
mask |= ROMFLAGS;
strcat(flagsmsg,"ROM ");
}
if (args[OPT_NOROM]) {
mask |= MAPP_ROM;
flags &= ~MAPP_ROM;
strcat(flagsmsg,"no ROM ");
}
if (args[OPT_WRITEPROTECTED]) {
flags &= ~ROMFLAGS;
flags |= MAPP_WRITEPROTECTED;
mask |= ROMFLAGS;
strcat(flagsmsg,"read only ");
}
if (args[OPT_NOTWRITEPROTECTED]) {
mask |= MAPP_WRITEPROTECTED;
flags &= ~MAPP_WRITEPROTECTED;
strcat(flagsmsg,"read/write ");
}
if (args[OPT_INVALID]) {
mask = 0xffffffff;
flags = MAPP_INVALID | MAPP_REPAIRABLE;
strcpy(flagsmsg,"invalid ");
}
if (args[OPT_BLANK]) {
mask = 0xffffffff;
flags = MAPP_BLANK;
strcpy(flagsmsg,"blank ");
}
which=WHICH_ALL;
whichmsg = "user and supervisor";
if (args[OPT_USERONLY]) {
which = WHICH_USER;
whichmsg = "user";
}
if (args[OPT_SUPERVISORONLY]) {
which=WHICH_SUPER;
whichmsg = "supervisor";
}
if (flagsmsg[0]=='\0') {
err=ERROR_REQUIRED_ARG_MISSING;
} else {
err=SetCacheMode((ULONG)from,(LONG)size,flags,mask,which);
if ((err==0) && args[OPT_VERBOSE]) {
Printf("%s.\n"
"Set %s mode from 0x%lx, size 0x%lx to %s\n",
version+6,whichmsg,from,size,flagsmsg);
}
}
}
}
FreeArgs(rd);
if (myrd) FreeDosObject(DOS_RDARGS,myrd);
if (msg) Close(SelectOutput(NULL));
} else err=IoErr();
if (msg) {
SelectOutput(oldout);
SetConsoleTask(oldconsole);
}
if (err<64) {
rc=err;
err=0;
} else {
if (!msg) PrintFault(err,"MuSetCacheMode failed");
rc=10;
}
SetIoErr(err);
CloseLibrary((struct Library *)MMUBase);
} else PrintFault(ERROR_OBJECT_NOT_FOUND,"MuSetCacheMode requires the mmu.library");
CloseLibrary((struct Library *)DOSBase);
}
return rc;
}
///
/// ReadTTArgs
struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp)
{
struct WBArg *wbarg;
struct DiskObject *dop;
char **tt; /* ToolTypes array */
char *wbstr; /* Our self-made workbench argument string */
char *here;
BPTR oldlock;
ULONG len;
struct RDArgs *rd=NULL,*myrd=NULL;
LONG err=0;
BPTR newout;
if (IconBase=OpenLibrary("icon.library",37L)) {
if (wbarg=msg->sm_ArgList) {
/* use a project icon if there is one... */
if (msg->sm_NumArgs > 1) wbarg++;
/* go into the directory */
oldlock=CurrentDir(wbarg->wa_Lock);
if (dop=GetDiskObject(wbarg->wa_Name)) {
if (tt=dop->do_ToolTypes) {
/* Read a special tool type for the output window */
/* Calc the size of the argument string */
len = 3; /* reserve space for SPC,LF,NUL */
while (*tt) {
len += strlen(*tt)+1; /* string, plus space */
tt++;
}
if (wbstr=AllocVec(len,MEMF_PUBLIC)) {
/* Now copy the arguments into this string, one by one
and check whether the argument string is still valid. */
tt=dop->do_ToolTypes;
here=wbstr;
do{
*here='\0'; /* terminate string */
/* Check whether this tool type is
commented out. Just ignore it in this case */
if (*tt) {
if (**tt=='(' || **tt==';')
continue;
strcpy(here,*tt); /* Add TT string */
}
len=strlen(here);
here[len]='\n';
here[len+1]='\0'; /* terminate string */
/* Now try to ReadArg' this string */
/* release old arguments left over from last loop */
if (rd) FreeArgs(rd);
if (myrd) FreeDosObject(DOS_RDARGS,myrd);
rd=NULL;
memset(args,0,sizeof(LONG)*OPT_COUNT);
if (myrd=AllocDosObject(DOS_RDARGS,NULL)) {
/* Allocate and setup the ReadArgs source */
myrd->RDA_Source.CS_Buffer=wbstr;
myrd->RDA_Source.CS_Length=strlen(wbstr);
if (rd=ReadArgs(TEMPLATE ",WINDOW/K",args,myrd)) {
/* Is this still valid? */
here[len]=' ';
here+=len+1;
/* if so, accept this argument and go on */
} else {
err=IoErr();
if (err==ERROR_NO_FREE_STORE) break;
else err=0; /* Ignore unknown or invalid arguments silently */
}
} else {
err=ERROR_NO_FREE_STORE;
break;
}
}while(*tt++);
FreeVec(wbstr);
} else err=ERROR_NO_FREE_STORE;
} else err=ERROR_REQUIRED_ARG_MISSING; /* Huh, how should this happen ? */
FreeDiskObject(dop);
} else err=IoErr();
CurrentDir(oldlock);
} else err=ERROR_REQUIRED_ARG_MISSING; /* This should not happen either */
CloseLibrary(IconBase);
} else err=ERROR_OBJECT_NOT_FOUND; /* This should not happen */
/* Open an output stream */
if (err==0) {
if (newout=Open((args[OPT_WINDOW])?((char *)args[OPT_WINDOW]):("NIL:"),MODE_NEWFILE)) {
SelectOutput(newout);
/* Hack in the output console. Well, well... */
SetConsoleTask(((struct FileHandle *)(BADDR(newout)))->fh_Type);
} else err=IoErr();
}
if (err) {
if (rd) FreeArgs(rd);
if (myrd) FreeDosObject(DOS_RDARGS,myrd);
SetIoErr(err);
rd=NULL;
myrd=NULL;
}
*tmp=myrd;
return rd;
}
///
/// SetCacheMode
int SetCacheMode(ULONG from,ULONG size,ULONG flags,ULONG mask,ULONG which)
{
struct MMUContext *ctx,*sctx; /* default context, supervisorcontext */
ULONG psize;
int err;
ctx=DefaultContext(); /* get the default context */
sctx=SuperContext(ctx); /* get the supervisor context for this one */
psize=GetPageSize(ctx);
if (size & (psize-1)) {
Printf("The given size 0x%lx is not divisible by the page size 0x%lx.\n",size,psize);
return ERROR_BAD_NUMBER;
}
if (from & (psize-1)) {
Printf("The given address 0x%lx is not divisible by the page size 0x%lx.\n",from,psize);
return ERROR_BAD_NUMBER;
}
if (psize!=GetPageSize(sctx)) {
Printf("MuSetCacheMode does not support different user and supervisor page sizes.\n");
return ERROR_OBJECT_WRONG_TYPE;
}
if (which & WHICH_USER) {
if (err=SetCache(ctx,from,size,flags,mask))
return err;
}
if (which & WHICH_SUPER) {
if (err=SetCache(sctx,from,size,flags,mask))
return err;
}
return 0;
}
///
/// SetCache
int SetCache(struct MMUContext *ctx,ULONG from,ULONG size,ULONG flags,ULONG mask)
{
struct MinList *ctxl;
if (ctxl=GetMapping(ctx)) {
if (SetProperties(ctx,flags,mask,from,size,TAG_DONE)) {
if (RebuildTree(ctx)) {
ReleaseMapping(ctx,ctxl);
return 0; /* Everything worked fine */
} /* the MMU tree could not be build. It is unmodified in this case */
}
/* Re-install the old properties. This can't fail. */
SetPropertyList(ctx,ctxl);
ReleaseMapping(ctx,ctxl);
}
return ERROR_NO_FREE_STORE;
}
///